home *** CD-ROM | disk | FTP | other *** search
- /*++
- /* NAME
- /* gtrans 3
- /* SUMMARY
- /* g protocol strategy functions
- /* PROJECT
- /* pc-mail
- /* PACKAGE
- /* cico
- /* SYNOPSIS
- /* #include "gp.h"
- /*
- /* int ginit(fd)
- /* int fd;
- /*
- /* Packet *galloc()
- /*
- /* void gsproto(fd,pk)
- /* int fd;
- /* Packet *pk;
- /*
- /* Packet *grproto(fd)
- /* int fd;
- /*
- /* void gfree(pk)
- /* Packet *pk;
- /*
- /* int gfinit(fd)
- /* int fd;
- /* DESCRIPTION
- /* ginit() exchanges the initial g protocol messages and allocates
- /* memory for packet buffers.
- /*
- /* galloc() returns a pointer to a free packet, after filling
- /* in its k and len fields. This packet is supposed to be filled
- /* with data, and to be subsequently queued with gsproto().
- /*
- /* grproto() extracts the next packet from the input queue.
- /* The packet should be returned to the free pool with gfree().
- /*
- /* gfinit() sends protocol termination messages until it receives one
- /* or until it gets bored.
- /* FUNCTIONS AND MACROS
- /* gsctrl(), gsdata(), grpack(), gfail()
- /* DIAGNOSTICS
- /* ginit(), gfinit() return a nonzero value if there was a problem.
- /*
- /* The other functions return through a call of gfail() in case of
- /* unrecoverable problems.
- /* BUGS
- /* Window size is equal to one. This implies that the program
- /* only sends new data when the previous packet was acknowledged.
- /* However, only the functions in *this* module need to be adapted
- /* to accomodate larger transmission window sizes.
- /* AUTHOR(S)
- /* W.Z. Venema
- /* Eindhoven University of Technology
- /* Department of Mathematics and Computer Science
- /* Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
- /* CREATION DATE
- /* Sun Apr 19 17:30:08 GMT+1:00 1987
- /* LAST MODIFICATION
- /* 90/01/22 13:01:44
- /* VERSION/RELEASE
- /* 2.1
- /*--*/
-
- #include "gp.h"
-
- /*
- * "The protocol is defined in terms of message transmissions of 8-bit bytes."
- * "Each message includes one control byte plus a data segment of zero or more"
- * "information bytes. The allowed data segment sizes range between 32 and"
- * "4096 as determined by the formula 32*2^k where k is a 3-bit number."
- */
-
- int seglen[] = { /* data segment sizes */
- 1,32,64,128,256,512,1024,2048,4096,
- };
-
- static int sndseg; /* data segment k-value they want */
- static int sndlen; /* data segment length they want */
- static int sndwin; /* transmission window size they want */
-
- #define ourseg 2 /* data segment k-value we want */
- #define ourlen 64 /* data segment length we want */
- #define ourwin 1 /* transmission window size we want */
-
- static Packet *inpk = 0; /* receive packet "pool" */
- static Packet *outpk = 0; /* send packet "pool" */
-
- static int rval = 0; /* our R value */
- static int sval = 1; /* our S value */
-
- /*
- * "Initial synchronization is accomplished with two 3-way handshakes:"
- * "two each of INITA/INITB/INITC. Each sender transmits INITA messages"
- * "repeatedly. When an INITA message is received, INITB is sent in return."
- * "When an INITB message is received *and* an INITB message has been sent,"
- * "an INITC message is sent. The INITA and INITB messages carry with them"
- * "the packet and window size that each receiver wants to use, and the"
- * "senders are supposed to comply. When a receiver has seen all three INIT"
- * "messages, the channel is considered to be open. (...) the INIT messages"
- * "are ignored elsewhere. (...)"
- * "After initial synchronization each receiver sets a modulo-8"
- * "incrementing counter R to 0; each sender sets a similar counter S to 1."
- * "The value of R is always the number of the most recent correctly received"
- * "packet. The value of S is always the first sequence number in the output"
- * "window."
- *
- * Since INIT messages are ignored once the channel has been opened, we
- * set the initial values of R and S at compile time.
- */
-
- /* ginit - g-protocol start-up */
-
- int ginit(fd)
- int fd;
- {
- register int state = 0;
- register int next = 0;
- int count = 0;
-
- /* set up receive packet buffers */
-
- if ((inpk = (Packet *) malloc((unsigned)sizeof(Packet)+ourlen)) == 0) {
- DEBUG(7,"gopen: malloc failed\n","");
- return(FAIL);
- }
-
- /*
- * Very simple automaton for initial message exchanges.
- * We send a packet, receive a packet and so on. The
- * automaton terminates when it reaches its accepting state,
- * when a time-out error occurs, or when it seems to get
- * stuck in one state.
- */
-
- while (state != INITC) {
-
- /* select action to be done in this state */
-
- switch (state) {
- case 0: /* initial state */
- gsctrl(fd,INITA|IFLD(ourwin)); /* send INITA message */
- break;
- case INITA: /* we received INITA */
- gsctrl(fd,INITB|IFLD(ourseg-1)); /* send INITB in response */
- break;
- case INITB: /* we received INITB */
- gsctrl(fd,INITC|IFLD(ourwin)); /* assume we sent INITB */
- break;
- }
-
- /*
- * Transition part of the automaton. Receive a packet and process
- * its contents. Depending on the packet and the current state
- * select a new state. Stay in the current state when a corrupted
- * packet is received or when we receive an unexpected packet.
- * If no packet is received assume we have lost contact and terminate.
- */
-
- switch (next = grpack(fd,inpk)) { /* see what we get */
- case INITA:
- sndwin = IVAL(inpk->c); /* transmission window size */
- state = next;
- break;
- case INITB:
- sndseg = IVAL(inpk->c)+1; /* send-segment type */
- sndlen = seglen[sndseg]; /* send-segment length */
- state = (state == INITA ? next : state);
- break;
- case INITC:
- state = (state == INITB ? next : state);
- break;
- case FAIL: /* corrupted message received */
- break;
- case TIME: /* no message received */
- return(FAIL);
- }
-
- /* check we don't stay in the same state forever */
-
- if (state == next) {
- count = 0;
- } else if (count++ > MAXTRY) {
- return(FAIL);
- }
- }
-
- /* set up transmission buffer "pool" */
-
- if ((outpk = (Packet *) malloc((unsigned)sizeof(Packet)+sndlen)) == 0) {
- DEBUG(7,"gopen: malloc failed\n","");
- return(FAIL);
- }
- return(0);
- }
-
- /*
- * The current version used a window size of 1, i.e. no further data
- * transmissions until the last transmitted data have been acknowledged.
- * The following routines anticipate on future versions with a real pool of
- * transmit and receive buffers.
- */
-
- /* galloc - allocate send packet, fill in size info */
-
- Packet *galloc()
- {
- register Packet *pk = outpk;
-
- pk->k = sndseg; /* data segment type */
- pk->len = sndlen; /* data segment size */
- return(pk);
- }
-
- /* gfree - release receive packet */
-
- void gfree(pk)
- register Packet *pk;
- {
- /* this function intentionally left blank */
- }
-
- /*
- * The central part of the protocol is in the routines gsproto() and
- * grproto(). These are the functions that negotiate with the other
- * host about what data to (re)transmit and to (n)ack.
- * Major changes are to be expected here when larger transmission
- * window sizes are to be supported.
- */
-
- /* gsproto - queue one packet for transmission */
-
- void gsproto(fd,pk)
- int fd;
- Packet *pk;
- {
- int numtry = 0; /* retry count */
-
- gsdata(fd,pk,SFLD(sval)|RFLD(rval)); /* send data packet */
-
- inpk->k = ourseg; /* "allocate" receive packet */
- inpk->len = ourlen;
-
- while (numtry < MAXTRY) {
- switch (grpack(fd,inpk)) { /* what is the reply */
- case SHORT: /* SHORT DATA */
- case DATA: /* LONG DATA */
- gsctrl(fd,RJ|RFLD(rval)); /* not now please */
- case RJ: /* REJECT */
- case RR: /* RECEIVER READY */
- if (RVAL(inpk->c) == sval) { /* check their R value */
- sval = (sval+1)&07; /* update our S value */
- return;
- }
- case FAIL: /* bad packet received */
- case TIME: /* no packet received */
- gsdata(fd,pk,SFLD(sval)|RFLD(rval));/* send data packet again */
- numtry++; /* but not forever */
- break;
- case CLOSE:
- gfail(); /* surprise! */
- /* NOTREACHED */
- }
- }
- gfail(); /* too may retries, abort */
- /* NOTREACHED */
- }
-
- /* grproto - take one packet from input queue */
-
- Packet *grproto(fd)
- int fd;
- {
- int numtry = 0; /* retry count */
- int xpct = (rval+1)&07; /* expected sequence nr */
- register Packet *pk = inpk; /* take one from the "pool" */
-
- pk->k = ourseg; /* initialize receive packet */
- pk->len = ourlen;
-
- while (numtry < MAXTRY) { /* don't loop forever */
- switch (grpack(fd,pk)) { /* see what we got */
- case DATA: /* LONG DATA */
- case SHORT: /* SHORT DATA */
- if (SVAL(pk->c) == xpct) { /* you're the 1 that I want */
- gsctrl(fd,RR|RFLD(rval = xpct));/* update R and acknowledge */
- return(pk); /* we are done here */
- } /* else ignore the packet */
- case FAIL: /* bad packet */
- gsctrl(fd,RJ|RFLD(rval)); /* reset their S value */
- case TIME: /* no packet, no nak */
- numtry++; /* don't loop forever */
- break; /* read another packet */
- case RR: /* RECEIVER READY */
- case RJ: /* REJECT */
- break; /* ignore */
- case CLOSE: /* surprise! */
- gfail(); /* boy, am I confused */
- /* NOTREACHED */
- }
- }
- gfail(); /* too may retries, abort */
- /* NOTREACHED */
- }
-
- /*
- * "The CLOSE message is used to terminate communications. Software on"
- * "either or both ends of the communication channel may initiate"
- * "termination. In any case when one end wants to terminate it sends"
- * "CLOSE messages until one is received from the other end or until a"
- * "programmable limit on the number of CLOSE messages is reached. Receipt"
- * "of a CLOSE message causes a CLOSE message to be sent."
- *
- * Normally systems decide together when to turn off the protocol so
- * that each system will start sending CLOSE messages at the same time.
- *
- * When a CLOSE message is received in the middle of a conversation
- * a protocol error is generated in grproto() or gsproto(). Then
- * gfinit() is called, so that the other system still sees a few CLOSE
- * messages.
- */
-
- /* gfinit - shut down the g protocol */
-
- int gfinit(fd)
- int fd;
- {
- register int numtry;
-
- for (numtry = 0; numtry < MAXTRY; numtry++) { /* programmable limit */
- gsctrl(fd,CLOSE); /* send CLOSE message */
- if (grpack(fd,inpk) == CLOSE) /* hope for same */
- return(0); /* got it */
- }
- return(FAIL); /* no CLOSE received */
- }
-